package base;

import java.util.LinkedList;
import java.util.Random;

public class Source
{
	private LinkedList<Element>	element_list;
	private int					samples;
	private int					distinct_element;
	private Gauss				gauss;
	private Random				rd;

	public Source(int seed)
	{
		rd = new Random(seed);
		
		samples = Simulator.getIntProperty("source.samples");
		
		distinct_element = Simulator.getIntProperty("source.distinct.element");	
		
		gauss = new Gauss(	Simulator.getIntProperty("gauss.rd.seed.x"),
							Simulator.getIntProperty("gauss.rd.seed.y"),
							Simulator.getIntProperty("gauss.m"),
							Simulator.getIntProperty("gauss.e"));

		generateElementList(generateDistinctElementList());
	}

	private LinkedList<Element> generateDistinctElementList()
	{
		LinkedList<Element> distinct_element_list = new LinkedList<Element>();
		for (int i = 0; i < distinct_element; i++)
		{
			distinct_element_list.add(new Element());
		}
		Element.resetGlobalId();
		return distinct_element_list;
	}

	private void generateElementList(LinkedList<Element> distinct_element_list)
	{
		double aNumber;
		double element_chance[] = generateElementChance();
		double sum_element_chance;
		element_list = new LinkedList<Element>();
		Element el, old_el = null;

		for (int i = 0; i < samples; i++)
		{
			aNumber = rd.nextDouble();
			sum_element_chance = 0;
			for (int j = 0; j < distinct_element; j++)
			{
				sum_element_chance += element_chance[j];

				if (aNumber < sum_element_chance)
				{
					el = (Element) distinct_element_list.get(j).clone();
					assignElementDateIn(el, old_el);
					element_list.add(el);
					old_el = el;
					break;
				}
			}
		}
	}

	private double[] generateElementChance()
	{
		double C = generateConstantC();
		double element_chance[] = new double[distinct_element];
		for (int i = 1; i <= distinct_element; i++)
		{
			element_chance[i - 1] = (double) C / (i * i);
		}
		return element_chance;
	}

	private double generateConstantC()
	{
		double sum = 0;
		for (int i = 1; i <= distinct_element; i++)
		{
			sum += (double) 1 / (i * i);
		}
		return 1 / sum;
	}

	private void assignElementDateIn(Element el, Element old_el)
	{
		double date_in;

		if (old_el == null)
		{
			date_in = 0;
		}
		else
		{
			date_in = old_el.getDateIn() + gauss.nextDouble();
		}
		el.setDateIn(date_in);
	}

	public LinkedList<Element> getElementList()
	{
		return element_list;
	}
}
